package com.example.controller;

import com.example.domain.Room;
import com.example.domain.Seat;
import com.example.domain.StudyRoomReservation;
import com.example.domain.User;
import com.example.dto.*;
import com.example.security.LoginUser;
import com.example.service.SeatService;
import com.example.service.StudyRoomReservationService;
import com.example.service.UserService;
import com.example.service.RoomService;
import com.example.util.Result;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.BeanUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 座位管理控制器
 * 
 * @author HP
 * @description 座位预约相关接口
 * @createDate 2025-08-26 20:00:00
 */
@Tag(name = "座位管理", description = "座位预约相关接口")
@RestController
@RequestMapping("/api")
public class SeatController {

    @Resource
    private SeatService seatService;

    @Resource
    private StudyRoomReservationService studyRoomReservationService;

    @Resource
    private UserService userService;

    @Resource
    private RoomService roomService;

    /**
     * 查询可用座位
     */
    @Operation(summary = "查询可用座位", description = "根据房间ID查询可用座位列表")
    @GetMapping("/seats/available")
    public Result getAvailableSeats(
            @Parameter(description = "房间ID，不传则查询所有房间") @RequestParam(required = false) Long roomId) {
        
        try {
            List<Seat> seats;
            if (roomId != null) {
                seats = (List<Seat>) seatService.getAvailableSeats(roomId).getData();
            } else {
                seats = seatService.getAvailableSeats();
            }

            // 转换为DTO
            List<SeatQueryResponseDTO> responseDTOs = new ArrayList<>();
            for (Seat seat : seats) {
                SeatQueryResponseDTO dto = new SeatQueryResponseDTO();
                BeanUtils.copyProperties(seat, dto);
                
                // 设置房间名称
                if (seat.getStudyRoomId() != null) {
                    dto.setRoomName("自习室" + seat.getStudyRoomId()); // 简化处理，实际应从Room表获取
                }
                
                dto.setCanReserve(seat.getSeatStatus() == 1);
                responseDTOs.add(dto);
            }

            return Result.success(responseDTOs);
        } catch (Exception e) {
            return Result.error("查询可用座位失败：" + e.getMessage());
        }
    }

    /**
     * 查询房间的所有座位
     */
    @Operation(summary = "查询房间座位", description = "查询指定房间的所有座位")
    @GetMapping("/seats/room/{roomId}")
    public Result getSeatsByRoomId(@Parameter(description = "房间ID") @PathVariable Long roomId) {
        
        try {
            List<Seat> seats = (List<Seat>) ((Map<String, Object>) seatService.getSeatsByRoomId(roomId).getData()).get("seats");
            
            List<SeatQueryResponseDTO> responseDTOs = new ArrayList<>();
            for (Seat seat : seats) {
                SeatQueryResponseDTO dto = new SeatQueryResponseDTO();
                BeanUtils.copyProperties(seat, dto);
                
                // 获取当前预约信息
                StudyRoomReservation currentReservation = studyRoomReservationService.getCurrentReservation(seat.getId());
                if (currentReservation != null) {
                    Result userResult = userService.getUserById(currentReservation.getUserId());
                    if (userResult != null && userResult.getData() != null) {
                        @SuppressWarnings("unchecked")
                        Map<String, Object> userData = (Map<String, Object>) userResult.getData();
                        User user = (User) userData.get("user");
                        if (user != null) {
                            dto.setCurrentUser(user.getUsername());
                            dto.setCurrentReservationStart(currentReservation.getStartTime().toString());
                            dto.setCurrentReservationEnd(currentReservation.getEndTime().toString());
                        }
                    }
                }
                
                dto.setCanReserve(seat.getSeatStatus() == 1);
                responseDTOs.add(dto);
            }

            return Result.success(responseDTOs);
        } catch (Exception e) {
            return Result.error("查询房间座位失败：" + e.getMessage());
        }
    }

    /**
     * 创建座位预约
     */
    @Operation(summary = "创建座位预约", description = "用户创建座位预约")
    @PostMapping("/reservations")
    @PreAuthorize("hasAnyRole('USER', 'ADMIN')")
    public Result createReservation(@Valid @RequestBody SeatReservationRequestDTO requestDTO, 
                                  HttpServletRequest request) {
        
        try {
            // 获取当前用户
            Long userId = getCurrentUserId();
            
            boolean success = studyRoomReservationService.createReservation(userId, requestDTO.getSeatId(), requestDTO.getStartTime(), requestDTO.getEndTime());

            if (success) {
                return Result.success("预约成功");
            } else {
                return Result.error("预约失败");
            }
        } catch (Exception e) {
            return Result.error("预约失败：" + e.getMessage());
        }
    }

    /**
     * 取消预约
     */
    @Operation(summary = "取消预约", description = "用户取消自己的预约")
    @DeleteMapping("/reservations/{reservationId}")
    @PreAuthorize("hasAnyRole('USER', 'ADMIN')")
    public Result cancelReservation(@Parameter(description = "预约ID") @PathVariable Long reservationId,
                                  HttpServletRequest request) {
        
        try {
            Long userId = getCurrentUserId();
            String ip = getClientIp(request);
            
            boolean success = studyRoomReservationService.cancelReservation(
                    reservationId, userId, userId, "用户取消", ip);

            if (success) {
                return Result.success("取消预约成功");
            } else {
                return Result.error("取消预约失败");
            }
        } catch (Exception e) {
            return Result.error("取消预约失败：" + e.getMessage());
        }
    }

    /**
     * 预约签到
     */
    @Operation(summary = "预约签到", description = "用户预约签到")
    @PostMapping("/reservations/{reservationId}/checkin")
    @PreAuthorize("hasAnyRole('USER', 'ADMIN')")
    public Result checkInReservation(@Parameter(description = "预约ID") @PathVariable Long reservationId) {
        
        try {
            Long userId = getCurrentUserId();
            
            boolean success = studyRoomReservationService.checkInReservation(reservationId, userId);

            if (success) {
                return Result.success("签到成功");
            } else {
                return Result.error("签到失败");
            }
        } catch (Exception e) {
            return Result.error("签到失败：" + e.getMessage());
        }
    }

    /**
     * 查询我的预约
     */
    @Operation(summary = "查询我的预约", description = "查询当前用户的预约记录")
    @GetMapping("/reservations/my")
    @PreAuthorize("hasAnyRole('USER', 'ADMIN')")
    public Result getMyReservations() {
        
        try {
            Long userId = getCurrentUserId();
            
            List<StudyRoomReservation> reservations = studyRoomReservationService.getUserReservations(userId);
            
            List<SeatReservationResponseDTO> responseDTOs = new ArrayList<>();
            for (StudyRoomReservation reservation : reservations) {
                SeatReservationResponseDTO dto = new SeatReservationResponseDTO();
                BeanUtils.copyProperties(reservation, dto);
                
                // 设置座位信息
                Seat seat = seatService.getById(reservation.getSeatId());
                if (seat != null) {
                    dto.setSeatNumber(seat.getNumber());
                    dto.setRoomId(seat.getStudyRoomId());
                    // 设置房间名称
                    Room room = roomService.getById(seat.getStudyRoomId());
                    if (room != null) {
                        dto.setRoomName(room.getName());
                    }
//                    dto.setRoomName("自习室" + seat.getStudyRoomId()); // 简化处理
                }
                
                // 设置用户信息
                dto.setUserId(userId);
                Result userResult = userService.getUserById(userId);
                if (userResult != null && userResult.getData() != null) {
                    @SuppressWarnings("unchecked")
                    Map<String, Object> userData = (Map<String, Object>) userResult.getData();
                    User user = (User) userData.get("user");
                    if (user != null) {
                        dto.setUsername(user.getUsername());
                    }
                }
                
                // 检查操作权限
                Map<String, Object> cancelCheck = studyRoomReservationService.canCancelReservation(reservation.getId(), userId);
                dto.setCanCancel((Boolean) cancelCheck.get("canCancel"));
                
                Map<String, Object> checkInCheck = studyRoomReservationService.canCheckInReservation(reservation.getId(), userId);
                dto.setCanCheckIn((Boolean) checkInCheck.get("canCheckIn"));
                
                responseDTOs.add(dto);
            }

            return Result.success(responseDTOs);
        } catch (Exception e) {
            return Result.error("查询预约记录失败：" + e.getMessage());
        }
    }

    /**
     * 查询座位今天的预约时间段
     */
    @Operation(summary = "查询座位今日预约时间段", description = "查询指定座位今天的所有预约时间段")
    @GetMapping("/seats/{seatId}/reservations/today")
    public Result getSeatTodayReservations(@Parameter(description = "座位ID") @PathVariable Long seatId) {
        
        try {
            if (seatId == null || seatId <= 0) {
                return Result.error("座位ID无效");
            }
            
            // 设置今天的开始和结束时间
            Date today = new Date();
            Calendar cal = Calendar.getInstance();
            cal.setTime(today);
            cal.set(Calendar.HOUR_OF_DAY, 0);
            cal.set(Calendar.MINUTE, 0);
            cal.set(Calendar.SECOND, 0);
            cal.set(Calendar.MILLISECOND, 0);
            Date startOfDay = cal.getTime();
            
            cal.set(Calendar.HOUR_OF_DAY, 23);
            cal.set(Calendar.MINUTE, 59);
            cal.set(Calendar.SECOND, 59);
            cal.set(Calendar.MILLISECOND, 999);
            Date endOfDay = cal.getTime();
            
            // 查询座位今天的预约记录
            List<StudyRoomReservation> reservations = studyRoomReservationService.getSeatReservations(seatId, startOfDay, endOfDay);
            
            // 过滤掉已取消的预约
            List<StudyRoomReservation> validReservations = reservations.stream()
                    .filter(reservation -> reservation.getReservationStatus() != 2) // 排除已取消
                    .collect(Collectors.toList());
            
            // 转换为响应DTO
            List<SeatReservationTimeSlotDTO> timeSlots = new ArrayList<>();
            for (StudyRoomReservation reservation : validReservations) {
                SeatReservationTimeSlotDTO timeSlot = new SeatReservationTimeSlotDTO();
                timeSlot.setReservationId(reservation.getId());
                timeSlot.setUserId(reservation.getUserId());
                timeSlot.setStartTime(reservation.getStartTime());
                timeSlot.setEndTime(reservation.getEndTime());
                timeSlot.setReservationStatus(reservation.getReservationStatus());
                timeSlot.setSignTime(reservation.getSignTime());
                
                // 获取用户信息
                Result userResult = userService.getUserById(reservation.getUserId());
                if (userResult != null && userResult.getData() != null) {
                    @SuppressWarnings("unchecked")
                    Map<String, Object> userData = (Map<String, Object>) userResult.getData();
                    User user = (User) userData.get("user");
                    if (user != null) {
                        timeSlot.setUsername(user.getUsername());
                    }
                }
                
                timeSlots.add(timeSlot);
            }
            
            // 按开始时间排序
            timeSlots.sort(Comparator.comparing(SeatReservationTimeSlotDTO::getStartTime));
            
            return Result.success(timeSlots);
        } catch (Exception e) {
            return Result.error("查询座位预约时间段失败：" + e.getMessage());
        }
    }
    
    /**
     * 查询预约统计信息
     */
    @Operation(summary = "查询预约统计", description = "查询座位预约统计信息")
    @GetMapping("/reservations/statistics")
    @PreAuthorize("hasAnyRole('ADMIN')")
    public Result getReservationStatistics(
            @Parameter(description = "座位ID") @RequestParam(required = false) Long seatId,
            @Parameter(description = "日期") @RequestParam(required = false) Date date) {
        
        try {
            Map<String, Object> statistics = studyRoomReservationService.getReservationStatistics(seatId, date);
            return Result.success(statistics);
        } catch (Exception e) {
            return Result.error("查询统计信息失败：" + e.getMessage());
        }
    }

    /**
     * 管理员强制取消预约
     */
    @Operation(summary = "管理员取消预约", description = "管理员强制取消用户预约")
    @DeleteMapping("/admin/reservations/{reservationId}")
    @PreAuthorize("hasRole('ADMIN')")
    public Result adminCancelReservation(@Parameter(description = "预约ID") @PathVariable Long reservationId,
                                       @Valid @RequestBody ReservationCancelRequestDTO requestDTO,
                                       HttpServletRequest request) {
        
        try {
            Long operatorId = getCurrentUserId();
            String ip = getClientIp(request);
            
            boolean success = studyRoomReservationService.adminCancelReservation(
                    reservationId, requestDTO.getReason(), operatorId, "管理员", ip);

            if (success) {
                return Result.success("管理员取消预约成功");
            } else {
                return Result.error("管理员取消预约失败");
            }
        } catch (Exception e) {
            return Result.error("管理员取消预约失败：" + e.getMessage());
        }
    }

    /**
     * 管理员代替签到
     */
    @Operation(summary = "管理员代替签到", description = "管理员代替用户签到")
    @PostMapping("/admin/reservations/{reservationId}/checkin")
    @PreAuthorize("hasRole('ADMIN')")
    public Result adminCheckInReservation(@Parameter(description = "预约ID") @PathVariable Long reservationId,
                                        HttpServletRequest request) {
        
        try {
            Long operatorId = getCurrentUserId();
            String ip = getClientIp(request);
            
            boolean success = studyRoomReservationService.adminCheckInReservation(
                    reservationId, operatorId, "管理员", ip);

            if (success) {
                return Result.success("管理员代替签到成功");
            } else {
                return Result.error("管理员代替签到失败");
            }
        } catch (Exception e) {
            return Result.error("管理员代替签到失败：" + e.getMessage());
        }
    }

    /**
     * 批量取消用户预约
     */
    @Operation(summary = "批量取消用户预约", description = "管理员批量取消指定用户的预约")
    @DeleteMapping("/admin/users/{userId}/reservations")
    @PreAuthorize("hasRole('ADMIN')")
    public Result batchCancelUserReservations(@Parameter(description = "用户ID") @PathVariable Long userId,
                                            @Parameter(description = "取消原因") @RequestParam(required = false) String reason,
                                            HttpServletRequest request) {
        
        try {
            Long operatorId = getCurrentUserId();
            String ip = getClientIp(request);
            
            int cancelledCount = studyRoomReservationService.batchCancelUserReservations(
                    userId, reason, operatorId, "管理员", ip);

            return Result.success("成功取消 " + cancelledCount + " 个预约");
        } catch (Exception e) {
            return Result.error("批量取消预约失败：" + e.getMessage());
        }
    }

    /**
     * 获取当前用户ID
     */
    private Long getCurrentUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() != null) {
            LoginUser loginUser = (LoginUser) authentication.getPrincipal();
            return loginUser.getId();
        }
        return null;
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}